package com.wxh.util;

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;

/**
 * @ClassName: SftpUtils
 * @Description: ssh ftp 安全文件传输协议
 * @Author wxh
 * @Date: 2019/12/2 10:22
 * @Version V1.0.0
 * @Since 1.8
 */
public class SftpUtils {

    private Logger logger = LoggerFactory.getLogger(SftpUtils.class);

    /**
     *  会话对象
     */
    private Session session = null;
    /**
     *  sftp通道对象
     */
    private ChannelSftp sftp = null;
    /**
     *  shell通道对象
     */
    private ChannelShell shell = null;
    /**
     * ssh主机IP
     */
    private String host;
    /**
     * shs端口
     */
    private int port;
    /**
     * ssh用户名
     */
    private String username;
    /**
     * ssh密码
     */
    private String password;
    /**
     * ssh key文件路径
     */
    private String keyFilePath;

    public SftpUtils(String host, int port, String username, String password, String keyFilePath) {
        logger.info("new sftp.host={}", host);
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
        this.keyFilePath = keyFilePath;
    }

    /**
     * 录sftp服务器
     */
    public void login() {
        try {
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");

            JSch jsch = new JSch();
            if (keyFilePath != null) {
                jsch.addIdentity(keyFilePath);
            }

            session = jsch.getSession(username, host, port);
            if (password != null) {
                session.setPassword(password);
            }
            session.setConfig(config);

            session.setConfig("kex", "diffie-hellman-group1-sha1");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;

            Channel channel1 = session.openChannel("shell");
            channel1.connect();
            shell = (ChannelShell) channel1;

            logger.info("login sftp success.host={},port={},username={}", new Object[]{host, port, username});
        } catch (JSchException e) {
            logger.info("login sftp error.host={},port={},username={},e={}", new Object[]{host, port, username, e});
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭连接
     */
    public void logout() {
        logger.info("logout");
        if (sftp != null && sftp.isConnected()) {
            sftp.disconnect();
        }
        if (shell != null && shell.isConnected()) {
            shell.disconnect();
        }
        if (session != null && session.isConnected()) {
            session.disconnect();
        }
        logger.info("logut success.");
    }

    /**
     * 将输入流的数据上传到sftp
     * @param directory   目录
     * @param fileName    文件名
     * @param inputStream 输入流
     * @throws Exception
     */
    public void upload(String directory, String fileName, InputStream inputStream) {
        logger.info("upload file.");
        try {
            sftp.cd(directory);
            logger.info("cd directory.");
        } catch (SftpException e) {
            logger.error("cd {} error.the directory may not exists.mkdir.", directory);
            try {
                sftp.mkdir(directory);
                sftp.cd(directory);
                logger.info("mkdir and cd directory.");
            } catch (SftpException e2) {
                logger.error("cd {} error.e={}", directory, e);
                throw new RuntimeException(e2);
            }
        }

        try {
            sftp.put(inputStream, fileName);
            logger.info("upload file {} success.", fileName);
        } catch (SftpException e) {
            logger.error("upload file {} error.e={}", fileName, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 下载文件
     * @param directory 下载目录
     * @param fileName  下载的文件名
     * @param localFile 本地路径（含文件名）
     * @throws Exception
     */
    public void download(String directory, String fileName, String localFile) {
        try {
            sftp.cd(directory);
            sftp.get(fileName, new FileOutputStream(localFile));
            logger.info("download file {} success", fileName);
        } catch (Exception e) {
            logger.error("download file {} error.e={}", fileName, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 下载文件到输入流
     * @param directory 下载目录
     * @param fileName  下载的文件名
     * @return 输入流
     * @throws Exception
     */
    public InputStream download(String directory, String fileName) {
        InputStream inputStream;
        try {
            sftp.cd(directory);
            inputStream = sftp.get(fileName);
        } catch (SftpException e) {
            logger.error("download file {} error.e={}", fileName, e);
            throw new RuntimeException(e);
        }
        return inputStream;
    }

    /**
     * 删除文件
     * @param directory 要删除文件所在目录
     * @param fileName  要删除的文件
     * @throws Exception
     */
    public void delete(String directory, String fileName) {
        try {
            sftp.cd(directory);
            sftp.rm(fileName);
            logger.info("delete file {} success.", fileName);
        } catch (SftpException e) {
            logger.error("delete file {} error.e={}", fileName, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行shell脚本
     * @param cmd shell脚本
     */
    public void execShellCmd(String cmd) {
        try {
            OutputStream os = shell.getOutputStream();
            os.write((cmd + "\nexit\n").getBytes());
            os.flush();
            os.close();
            logger.info("shell success.cmd={}", cmd);

            BufferedReader br = new BufferedReader(new InputStreamReader(shell.getInputStream()));
            String str;
            while ((str = br.readLine()) != null) {
                logger.info(str);
            }
            br.close();
        } catch (Exception e) {
            logger.error("shell error.cmd={},e={}", cmd, e);
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        SftpUtils sftp = new SftpUtils("192.168.95.156", 22, "storm", "storm", null);
        sftp.login();
        sftp.execShellCmd("cd /app/storm\nmv lqx.txt4321 lqx.lqx");
        sftp.logout();
    }


}
